<!-- 高级表格 -->
<template>
  <EleLoading v-bind="loadingProps">
    <slot name="topExtra"></slot>
    <!-- 工具栏 -->
    <EleToolbar
      v-if="tableToolbarProps"
      v-bind="tableToolbarProps === true ? {} : tableToolbarProps"
    >
      <slot name="toolbar"></slot>
      <template #tools>
        <slot name="tools"></slot>
        <TableTools
          v-if="toolNames && toolNames.length"
          ref="tableToolsRef"
          :tools="toolNames"
          :tableState="tableState"
          :size="tableSize"
          :columns="columns"
          :columnSortable="columnSortable"
          :columnFixed="columnFixed"
          :maximized="tableMaximized"
          :cacheKey="cacheKey"
          :locale="locale"
          :selections="selections"
          :pageData="tableData"
          :spanMethod="spanMethod"
          :tableHeader="showHeader"
          :showSummary="showSummary"
          :sumText="sumText"
          :summaryMethod="summaryMethod"
          :tableStyle="tableStyle"
          :cellStyle="cellStyle"
          :cellClassName="cellClassName"
          :headerCellStyle="headerCellStyle"
          :headerCellClassName="headerCellClassName"
          :pageIndex="tableIndex"
          :treeProps="treeProps"
          :fetch="fetch"
          :exportConfig="toolExportConfig"
          :printConfig="toolPrintConfig"
          @reload="handleRefresh"
          @update:size="handleSizeChange"
          @update:columns="handleColumnsChange"
          @update:maximized="handleMaximizedChange"
        >
          <template
            v-for="name in Object.keys($slots).filter(
              (k) => !toolsSlotExcludes.includes(k),
            )"
            #[name]="slotProps"
          >
            <slot :name="name" v-bind="slotProps || {}"></slot>
          </template>
        </TableTools>
      </template>
    </EleToolbar>
    <slot></slot>
    <!-- 表格 -->
    <EleVirtualTable v-if="virtual" v-bind="tableProps" ref="tableViewRef">
      <template
        v-for="name in Object.keys($slots).filter(
          (k) => !tableSlotExcludes.includes(k),
        )"
        #[name]="slotProps"
      >
        <slot :name="name" v-bind="slotProps || {}"></slot>
      </template>
    </EleVirtualTable>
    <EleDataTable v-else v-bind="tableProps" ref="tableViewRef">
      <template
        v-for="name in Object.keys($slots).filter(
          (k) => !tableSlotExcludes.includes(k),
        )"
        #[name]="slotProps"
      >
        <slot :name="name" v-bind="slotProps || {}"></slot>
      </template>
    </EleDataTable>
    <!-- 底栏 -->
    <div
      v-if="paginationProps || $slots.footer"
      class="ele-pro-table-footer"
      :style="footerStyle"
    >
      <slot name="footer"></slot>
      <ElePagination
        v-if="paginationProps && paginationProps.total"
        v-bind="paginationProps"
        @update:currentPage="handlePageCurrentChange"
        @update:pageSize="handlePageSizeChange"
      >
        <template
          v-for="name in Object.keys($slots).filter(
            (k) => !pageSlotExcludes.includes(k),
          )"
          #[name]="slotProps"
        >
          <slot :name="name" v-bind="slotProps || {}"></slot>
        </template>
      </ElePagination>
    </div>
    <slot name="bottomExtra"></slot>
  </EleLoading>
</template>

<script setup>
import { ref, shallowRef, computed, watch, onMounted, nextTick } from "vue";
import { pick, getValue } from "../utils/common";
import { useGlobalProps } from "../ele-config-provider/receiver";
import EleLoading from "../ele-loading/index.vue";
import ElePagination from "../ele-pagination/index.vue";
import { dataTablePropKeys } from "../ele-data-table/props";
import {
  useEmits,
  useMethods,
  getRowKeys,
  arrayIsChanged,
} from "../ele-data-table/util";
import EleDataTable from "../ele-data-table/index";
import EleVirtualTable from "../ele-virtual-table/index.vue";
import EleToolbar from "../ele-toolbar/index.vue";
import TableTools from "./components/table-tools.vue";
import {
  getTablePage,
  getTableLimit,
  getPaginationProps,
  getTableSize,
  getDefaultFilter,
  getResponseName,
  getRequestOrders,
  getRequestFilters,
  getRequestPages,
  getResponseResult,
  reloadData,
  sortData,
  isAutoAmend,
  getInitCacheColumns,
  cacheColWidth,
  mergeProps,
  getRowKey,
} from "./util";
import { proTableProps, proTableEmits } from "./props";
const ownSlots = [
  "default",
  "toolbar",
  "tools",
  "footer",
  "topExtra",
  "bottomExtra",
];
const toolsSlotExcludes = [...ownSlots, "empty", "append"];
const tableSlotExcludes = [...ownSlots, "printTop", "printBottom"];
const pageSlotExcludes = [...toolsSlotExcludes, "printTop", "printBottom"];

defineOptions({ name: "EleProTable" });

const props = defineProps(proTableProps);

const emit = defineEmits(proTableEmits);

const events = useEmits(emit);
const methods = useMethods(() => getTableRef());
const globalProps = useGlobalProps("table");
const virtualTableEvents = {
  onEndEeached: (params) => {
    emit("endEeached", params);
  },
  onScroll: (params) => {
    emit("scroll", params);
  },
  onRowsRendered: (params) => {
    emit("rowsRendered", params);
  },
};

/** 表格当前的排序筛选搜索参数 */
const tableState = {
  sorter: props.defaultSort ?? {},
  filter: getDefaultFilter(props.columns),
  where: props.where ?? {},
};

/** 表头工具组件 */
const tableToolsRef = ref(null);

/** 表格组件 */
const tableViewRef = ref(null);

/** 当前页数据 */
const tableData = ref([]);

/** 当前页码 */
const tablePage = ref(
  getTablePage(props.pagination, globalProps.value.pagination),
);

/** 每页显示数量 */
const tableLimit = ref(
  getTableLimit(props.pagination, globalProps.value.pagination),
);

/** 数据总数量 */
const tableTotal = ref(0);

/** 数据请求状态 */
const tableLoading = ref(props.loading);

/** 表格列配置 */
const tableCols = ref([]);

/** 表格尺寸 */
const tableSize = ref(
  getTableSize(props.cacheKey, props.size, globalProps.value.size),
);

/** 是否最大化 */
const tableMaximized = ref(false);

/** 错误信息 */
const errorText = ref("");

/** 缓存数据 */
const cacheData = ref();

/** 表格的rowKey */
const tableRowKey = shallowRef(getRowKey(props.rowKey));

/** 表格索引开始序号 */
const tableIndex = computed(() => {
  return ((tablePage.value ?? 1) - 1) * (tableLimit.value ?? 0) + 1;
});

/** 表格当前索引开始序号 */
const tableCurrentIndex = ref(tableIndex.value);

/** 分页组件属性 */
const paginationProps = computed(() => {
  return getPaginationProps(
    tableSize.value,
    props.pagination,
    globalProps.value.pagination,
    {
      total: tableTotal.value,
      pageSize: tableLimit.value,
      currentPage: tablePage.value,
      hasNext: tableData.value.length >= tableLimit.value,
    },
  );
});

/** 空组件属性 */
const tableEmptyProps = computed(() => {
  return mergeProps(props.emptyProps, globalProps.value.emptyProps);
});

/** 是否是方法数据源 */
const isFunctionSource = computed(() => {
  return typeof props.datasource === "function";
});

/** 表格组件属性 */
const tableProps = computed(() => {
  const isMaximized = tableMaximized.value && props.maximizedHeight;
  const options = {
    ...pick(props, dataTablePropKeys),
    height: isMaximized ? props.maximizedHeight : props.height,
    border: props.border ?? globalProps.value.border ?? false,
    stripe: props.stripe ?? globalProps.value.stripe ?? false,
    load: tableLoad,
    size: tableSize.value,
    data: tableData.value,
    columns: tableCols.value,
    cacheData: cacheData.value,
    errorText: errorText.value,
    pageIndex: tableCurrentIndex.value,
    emptyProps: tableEmptyProps.value,
    rowHeight: props.virtual ? props.rowHeight : void 0,
    rowKey: tableRowKey.value,
    style: props.tableStyle,
    class: "ele-pro-table-view",
    ...events,
    onSelectionChange: handleSelectionChange,
    onSortChange: handleSortChange,
    onFilterChange: handleFilterChange,
    onCurrentChange: handleCurrentChange,
    onHeaderDragend: handleHeaderDragend,
  };
  if (props.virtual) {
    Object.assign(options, virtualTableEvents);
  }
  return options;
});

/** 表格工具按钮布局 */
const toolNames = computed(() => {
  const tools = props.tools ?? globalProps.value.tools ?? true;
  if (tools === true) {
    return ["reload", "size", "columns", "maximized"];
  }
  return tools || [];
});

/** 表头工具栏属性 */
const tableToolbarProps = computed(() => {
  return mergeProps(props.toolbar, globalProps.value.toolbar);
});

/** 表格导出配置 */
const toolExportConfig = computed(() => {
  const globalExportConfig = globalProps.value.exportConfig || {};
  const userExportConfig = props.exportConfig || {};
  console.log(userExportConfig);
  userExportConfig.tableName = userExportConfig.tableName
    ? userExportConfig.tableName
    : props.cacheKey;
  return {
    ...globalExportConfig,
    ...userExportConfig,
    modalProps: {
      ...(globalExportConfig.modalProps || {}),
      ...(userExportConfig.modalProps || {}),
    },
  };
});

/** 表格打印配置 */
const toolPrintConfig = computed(() => {
  const globalPrintConfig = globalProps.value.printConfig || {};
  const userPrintConfig = props.printConfig || {};
  return {
    ...globalPrintConfig,
    ...userPrintConfig,
    modalProps: {
      ...(globalPrintConfig.modalProps || {}),
      ...(userPrintConfig.modalProps || {}),
    },
    printerProps: {
      ...(globalPrintConfig.printerProps || {}),
      ...(userPrintConfig.printerProps || {}),
    },
    tableProps: {
      ...(globalPrintConfig.tableProps || {}),
      ...(userPrintConfig.tableProps || {}),
    },
  };
});

/** 根节点属性 */
const loadingProps = computed(() => {
  const zIndex = props.maximizedIndex ?? globalProps.value.maximizedIndex;
  return {
    ...(props.loadingProps || {}),
    loading: tableLoading.value,
    class: [
      "ele-pro-table",
      { "is-maximized": tableMaximized.value },
      { "is-border": tableProps.value.border },
    ],
    style: tableMaximized.value ? { zIndex } : void 0,
  };
});

/** 加载数据 */
const reload = (option, parent, resolve) => {
  if (option) {
    if (option.page) {
      tablePage.value = option.page;
    }
    if (option.limit) {
      tableLimit.value = option.limit;
    }
    if (option.where) {
      tableState.where = option.where;
    }
    if (option.sorter) {
      tableState.sorter = option.sorter;
    }
    if (option.filter) {
      tableState.filter = option.filter;
    }
  }
  errorText.value = "";
  const sorter = tableState.sorter;
  // 直接指定数据
  if (!isFunctionSource.value) {
    const { data, page, total } = reloadData(
      props.datasource,
      sorter,
      paginationProps.value ? tablePage.value : void 0,
      tableLimit.value,
    );
    cacheData.value = props.datasource;
    tableData.value = data;
    tablePage.value = page;
    tableTotal.value = total;
    handleDone({ data, page, total, response: props.datasource });
    return;
  }
  // 自定义请求方法
  if (!parent) {
    tableLoading.value = true;
  }
  const filter = tableState.filter;
  const orders = getRequestOrders(
    sorter,
    props.request,
    globalProps.value.request,
  );
  props
    .datasource({
      page: tablePage.value,
      limit: tableLimit.value,
      pages: getRequestPages(
        tablePage.value,
        tableLimit.value,
        props.request,
        globalProps.value.request,
      ),
      where: Object.assign({}, tableState.where),
      orders,
      filters: getRequestFilters(filter),
      sorter,
      filter,
      parent,
    })
    .then((response) => {
      const parseData = props.parseData ?? globalProps.value.parseData;
      const result = parseData ? parseData(response) : response;
      const { data, total } = getResponseResult(
        result,
        props.response,
        globalProps.value.response,
        props.lazy,
        props.treeProps,
      );
      requestCallback(data, total, parent, result, resolve);
    })
    .catch((e) => {
      const errorMsg = e?.message;
      requestCallback(
        errorMsg == null ? errorMsg : String(errorMsg),
        void 0,
        parent,
        e,
        resolve,
      );
      resolve && console.error(e);
    });
};

/** 请求数据回调 */
const requestCallback = (data, total, parent, response, resolve) => {
  if (data == null || !Array.isArray(data)) {
    if (resolve) {
      if (parent != null) {
        parent[props.treeProps?.children || "children"] = [];
      }
      resolve([]);
    } else {
      tableData.value = [];
    }
    tableLoading.value = false;
    if (typeof data === "string" && data) {
      errorText.value = data;
      return;
    }
    errorText.value = "获取数据失败";
    console.error(
      "返回的数据格式与配置的不一致, 返回的数据:",
      response,
      "需要的格式:",
      getResponseName(globalProps.value.response, props.response),
    );
    return;
  }
  if (resolve) {
    if (parent != null) {
      parent[props.treeProps?.children || "children"] = data;
    }
    resolve(data);
  } else {
    // 自动修正页码
    if (
      isAutoAmend(props.pagination, globalProps.value.pagination) &&
      !data.length &&
      total &&
      "*" !== total &&
      tablePage.value &&
      tableLimit.value
    ) {
      const maxPage = Math.ceil(total / tableLimit.value);
      if (maxPage && tablePage.value > maxPage) {
        tablePage.value = maxPage;
        reload();
        return;
      }
    }
    // 获取返回的数据
    tableData.value = data;
    tableTotal.value = total || data.length;
  }
  tableLoading.value = false;
  const result = {
    data: tableData.value,
    page: tablePage.value,
    total: tableTotal.value,
    response,
  };
  handleDone(result, parent);
};

/** 树形表格懒加载 */
const tableLoad = (row, treeNode, resolve) => {
  if (props.load) {
    props.load(row, treeNode, resolve);
    return;
  }
  reload(void 0, row, resolve);
};

/** 表格数据渲染完成 */
const handleDone = (result, parent) => {
  checkTableCurrentIndex();
  nextTick(() => {
    if (props.current != null) {
      methods.setCurrentRowKey(getValue(props.current, tableRowKey.value));
    }
    if (props.selections != null && props.selections.length) {
      methods.setSelectedRowKeys(
        getRowKeys(props.selections, tableRowKey.value),
      );
    }
  });
  emit("done", result, parent);
};

/** 刷新按钮事件 */
const handleRefresh = () => {
  if (isFunctionSource.value) {
    reload();
    return;
  }
  emit("refresh");
};

/** 尺寸改变事件 */
const handleSizeChange = (size) => {
  tableSize.value = size;
  emit("sizeChange", size);
};

/** 列配置改变事件 */
const handleColumnsChange = (columns, tableColumns, isReset) => {
  tableCols.value = columns;
  emit("columnsChange", columns, tableColumns, isReset);
};

/** 全屏切换事件 */
const handleMaximizedChange = (maximized) => {
  tableMaximized.value = maximized;
  emit("maximizedChange", maximized);
};

/** 分页数量改变事件 */
const handlePageSizeChange = (limit) => {
  if (tableLimit.value !== limit) {
    tableLimit.value = limit;
    if (tableTotal.value !== "*") {
      const maxPage = Math.ceil(tableTotal.value / limit);
      if (maxPage && tablePage.value > maxPage) {
        tablePage.value = maxPage;
      }
    }
    reload();
  }
};

/** 分页页码改变事件 */
const handlePageCurrentChange = (page) => {
  if (tablePage.value !== page) {
    tablePage.value = page;
    reload();
  }
};

/** 排序方式改变事件 */
const handleSortChange = (sorter) => {
  if (props.loadOnChanged) {
    tableState.sorter = sorter;
    reload();
  }
  events.onSortChange(sorter);
};

/** 筛选条件改变事件 */
const handleFilterChange = (filter) => {
  if (props.loadOnChanged) {
    tableState.filter = filter;
    reload();
  }
  events.onFilterChange(filter);
};

/** 表头列宽拉伸改变事件 */
const handleHeaderDragend = (newWidth, oldWidth, column, event) => {
  cacheColWidth(newWidth, column, props.cacheKey);
  events.onHeaderDragend(newWidth, oldWidth, column, event);
};

/** 单选当前行改变事件 */
const handleCurrentChange = (currentRow, oldCurrentRow) => {
  updateCurrent(currentRow);
  events.onCurrentChange(currentRow, oldCurrentRow);
};

/** 选择项改变事件 */
const handleSelectionChange = (selection) => {
  updateSelections(selection);
  events.onSelectionChange(selection);
};

/** 更新单选选中数据 */
const updateCurrent = (currentRow) => {
  if (currentRow !== props.current) {
    emit("update:current", currentRow);
  }
};

/** 更新多选选中数据 */
const updateSelections = (selection) => {
  if (arrayIsChanged(selection, props.selections)) {
    emit("update:selections", selection);
  }
};

/** 检查表格当前索引开始序号 */
const checkTableCurrentIndex = () => {
  if (tableCurrentIndex.value !== tableIndex.value) {
    tableCurrentIndex.value = tableIndex.value;
  }
};

/** 重置表格 */
const reloadTable = () => {
  methods.doLayout();
};

/** 获取表格实例 */
const getTableRef = () => {
  return tableViewRef.value;
};

/** 获取当前页数据 */
const getData = () => {
  return tableData.value;
};

/** 修改当前页数据 */
const setData = (data) => {
  tableData.value = data;
  checkTableCurrentIndex();
};

/** 前端分页时跳转页码到对应数据 */
const goPageByRowKey = (key) => {
  if (
    !paginationProps.value ||
    tableLimit.value == null ||
    isFunctionSource.value
  ) {
    return;
  }
  const rowKey = tableRowKey.value;
  const data = sortData(props.datasource, tableState.sorter);
  const index = data.findIndex((d) => getValue(d, rowKey) === key);
  const page = Math.floor(index / tableLimit.value) + 1;
  if (tablePage.value !== page) {
    reload({ page });
  }
};

/** 获取请求参数 */
const fetch = (callback) => {
  const { sorter, filter } = tableState;
  const orders = getRequestOrders(
    sorter,
    props.request,
    globalProps.value.request,
  );
  callback({
    page: tablePage.value,
    limit: tableLimit.value,
    pages: getRequestPages(
      tablePage.value,
      tableLimit.value,
      props.request,
      globalProps.value.request,
    ),
    where: Object.assign({}, tableState.where),
    orders,
    filters: getRequestFilters(filter),
    sorter,
    filter,
  });
};

/** 打开打印弹窗 */
const openPrintModal = () => {
  if (tableToolsRef.value) {
    tableToolsRef.value.openPrintModal();
  }
};

/** 直接打印数据 */
const printData = (params) => {
  if (tableToolsRef.value) {
    tableToolsRef.value.printData(params);
  }
};

/** 打开导出弹窗 */
const openExportModal = () => {
  if (tableToolsRef.value) {
    tableToolsRef.value.openExportModal();
  }
};

/** 直接导出数据 */
const exportData = (params) => {
  if (tableToolsRef.value) {
    tableToolsRef.value.exportData(params);
  }
};

watch(
  () => props.columns,
  (columns) => {
    if (columns) {
      tableCols.value = getInitCacheColumns(
        columns,
        props.cacheKey,
        props.columnSortable,
      );
    } else if (tableCols.value.length) {
      tableCols.value = [];
    }
  },
  { immediate: true, deep: true },
);

watch(
  () => props.datasource,
  () => {
    reload();
  },
  { deep: true },
);

watch(
  () => props.loading,
  (loading) => {
    tableLoading.value = loading;
  },
);

watch(
  () => props.size,
  (size) => {
    tableSize.value = getTableSize(void 0, size, globalProps.value.size);
  },
);

watch(
  () => props.current,
  (current) => {
    methods.setCurrentRowKey(getValue(current, tableRowKey.value));
  },
);

watch(
  () => props.selections,
  (selections) => {
    methods.setSelectedRowKeys(getRowKeys(selections, tableRowKey.value));
  },
);

watch(
  () => props.rowKey,
  () => {
    tableRowKey.value = getRowKey(props.rowKey);
  },
);

watch(
  globalProps,
  (config) => {
    tableSize.value = getTableSize(props.cacheKey, props.size, config.size);
  },
  { deep: true },
);

onMounted(() => {
  if (props.loadOnCreated) {
    reload();
  }
});

defineExpose({
  ...methods,
  tableToolsRef,
  tableViewRef,
  tableData,
  tableLoading,
  tableProps,
  reload,
  reloadTable,
  getTableRef,
  getData,
  setData,
  goPageByRowKey,
  fetch,
  openPrintModal,
  printData,
  openExportModal,
  exportData,
});
</script>
